/*
 * 内核线程实例
 */

#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/err.h>
#include <linux/version.h>
#include <linux/delay.h>

static int task_A_thread(void* arg)
{
	int count = 1;
	
	// 获取当前 内核线程/task
	struct task_struct* current_task = current;
	pr_info("task state=%x\n", current_task->flags);
	while (!kthread_should_stop())
	{
		pr_info("task_A_thread running %d, state=%x\n", count, current_task->__state);
		msleep(1000);
		count++;
	}
	pr_info("task a exit: state=%x\n", current_task->flags);

	return 0;
}

static int task_B_thread(void* arg)
{
	int count;
	count = *(int *)arg;

	pr_info("arg point=%p\n",arg);
	while (!kthread_should_stop())
	{
		pr_info("task_B_thread running --> %d\n", count);
		msleep(1000);
		count--;
	}

	return 0;
}

struct task_struct* task_a;
struct task_struct* task_b;
int num = 5;
static int __init completions_init(void)
{
	pr_info("kthread and task_struct example\n");
	task_a = kthread_create(task_A_thread, NULL, "task_a_thread");
	if (IS_ERR(task_a))
		goto ERROR_THREAD_1;

	pr_info("num point=%p, %d\n",&num,num);
	task_b = kthread_create(task_B_thread, &num, "task_b_thread");
	if (IS_ERR(task_b))
		goto ERROR_THREAD_2;

	wake_up_process(task_a);
	wake_up_process(task_b);

	// mdelay(1000);
	pr_info("num point=%d\n",num);

	return 0;

ERROR_THREAD_2:
	kthread_stop(task_a);
ERROR_THREAD_1:

	return -1;
}

static void __exit completions_exit(void)
{
	int count = 0;
	pr_info("task_a state=%x\n",task_a->__state);
	kthread_stop(task_a);
	kthread_stop(task_b);

	while(task_a->__state != TASK_DEAD && count < 5){
		pr_info("task_a not stop\n");
		mdelay(1000);
		count ++;
	}
	pr_info("task_a has stop, __state=%x\n",task_a->__state);

	count = 0;
	while(task_b->__state != TASK_DEAD && count < 5){
		pr_info("task_b not stop\n");
		mdelay(1000);
		count ++;
	}
	pr_info("task_b has stop, __state=%x\n",task_b->__state);

	pr_info("completions exit\n");
}

module_init(completions_init);
module_exit(completions_exit);

MODULE_DESCRIPTION("Completions example");
MODULE_LICENSE("GPL");

/* 测试:

 */
